﻿using System;
using System.Threading;

namespace _1116._打印零与奇偶数
{
    /// <summary>
    /// https://leetcode.cn/problems/print-zero-even-odd/
    /// </summary>
    public class ZeroEvenOdd
    {
        private int n;

        public ZeroEvenOdd(int n)
        {
            this.n = n;
        }

        System.Threading.Semaphore sema0 = new System.Threading.Semaphore(1, 1);
        System.Threading.Semaphore sema1 = new System.Threading.Semaphore(0, 1);
        System.Threading.Semaphore sema2 = new System.Threading.Semaphore(0, 1);

        // printNumber(x) outputs "x", where x is an integer.
        // 仅打印出 0
        public void Zero(Action<int> printNumber)
        {
            for (int i = 0; i < n; i += 1)
            {
                sema0.WaitOne();

                printNumber(0);

                if (i % 2 == 0)
                {
                    sema1.Release();
                }
                else
                {
                    sema2.Release();
                }
            }
        }
        //even打印偶数
        public void Even(Action<int> printNumber)
        {
            for (int i = 2; i <= n; i += 2)
            {
                sema2.WaitOne();
                printNumber(i);
                sema0.Release();
            }
        }
        //用odd打印奇数，
        public void Odd(Action<int> printNumber)
        {
            for (int i = 1; i <= n; i += 2)
            {
                sema1.WaitOne();
                printNumber(i);
                sema0.Release();
            }
        }
    }
    class Program
    {
        static ZeroEvenOdd foo = new ZeroEvenOdd(2);

        static void Main(string[] args)
        {

            Thread thread = new Thread(new ParameterizedThreadStart(Zero));
            thread.Name = $"Zero";
            thread.Start(thread.Name);

            Thread thread2 = new Thread(new ParameterizedThreadStart(Even));
            thread2.Name = $"Even";
            thread2.Start(thread2.Name);

            Thread thread3 = new Thread(new ParameterizedThreadStart(Odd));
            thread3.Name = $"Odd";
            thread3.Start(thread3.Name);
        }

        static void Zero(object obj)
        {
            foo.Zero((num) =>
            {
                Console.WriteLine("A:" + num);
            });
        }
        static void Even(object obj)
        {
            foo.Even((num) =>
            {
                Console.WriteLine("B:" + num);
            });
        }
        static void Odd(object obj)
        {
            foo.Odd((num) =>
            {
                Console.WriteLine("C:" + num);
            });
        }
    }
}
